/*===============================================================
 *   Copyright (C) 2017 All rights reserved.
 *   
 *   文件名称：lib.c
 *   创 建 者：陈迪林
 *   创建日期：2017年08月02日
 *   描    述：
 *
 *   更新日志：
 *
 ================================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <dirent.h>
#include <time.h>
#include "lib.h"

#include <sqlite3.h>

int user_num=0;
pthread_mutex_t flag;
USER_INFO user_info[MAXUSER];

/* sqlite3 */
int usrinfo_callback(void *para, int f_num, char **f_value, char **f_name)
{
    int i;

    char *pPara = (char *)para;

    if(0 == strncmp(f_value[0],pPara,20) && 0 == strncmp(f_value[1], pPara+20,20))
    {
        pPara[40] = 1;
    }
    return 0;
}

int exists_callback(void *para, int f_num, char **f_value, char **f_name)
{
    int i;

    char *pPara = (char *)para;

    if(0 == strncmp(f_value[0],pPara,20))
    {
        pPara[20] = 1;
    }

    return 0;
}


int validate_userexists(const char *name)
{
    sqlite3 *db;
    
    if(sqlite3_open("user_data.db",&db) != SQLITE_OK)
    {
        printf("error: %s\n",sqlite3_errmsg(db));
        return -1;
    }
    
    char *errmsg;

    char para[21];
    bzero(para,21);

    memcpy(para, name, 20);
    
    if(SQLITE_OK != sqlite3_exec(db,"select * from user_info", exists_callback, para, &errmsg))
    {
        printf("error: %s\n",errmsg);
        return -1;
    }

    sqlite3_close(db);

    if(para[20] == 0)return 0; /* 若用户不存在 para[20]=0 */
    else return -1;
}

int validate_userinfo(const char *name, const char *passwd)
{
    sqlite3 *db;
    
    if(sqlite3_open("user_data.db",&db) != SQLITE_OK)
    {
        printf("error: %s\n",sqlite3_errmsg(db));
        return -1;
    }
    
    char *errmsg;

    char para[41];
    bzero(para,41);

    memcpy(para, name, 20);
    memcpy(para+20, passwd, 20);
    
    if(SQLITE_OK != sqlite3_exec(db,"select * from user_info", usrinfo_callback, para, &errmsg))
    {
        printf("error: %s\n",errmsg);
        return -1;
    }

    sqlite3_close(db);

    if(para[40] == 1)return 0; /* 若验证成功 para[40]=1 */
    else return -1;

}

int insert_sqlite(const char *name, const char *passwd)
{
    if(0 != validate_userexists(name))
    {
        return 2;
    }
    sqlite3 *db;
    
    if(sqlite3_open("user_data.db",&db) != SQLITE_OK)
    {
        printf("error: %s\n",sqlite3_errmsg(db));
        return -1;
    }
    
    char *errmsg;

    char buff[100];
    sprintf(buff,"insert into user_info values(\"%s\",\"%s\")", name,passwd);

    if(SQLITE_OK != sqlite3_exec(db, buff, NULL, NULL, &errmsg))
    {
        printf("error: %s\n",errmsg);
        return -1;
    }

    sqlite3_close(db);
    return 0;
}

int findsockbyname(const char *name)
{
    int i = 0;
    for(;i<user_num;i++)
    {
        if(0 == strcmp(user_info[i].id, name))
        {
            return user_info[i].sock;
        }
    }
    return -1;
}

void send_usrinfo()
{
    USER_DATA usr_data;
    bzero(&usr_data,DATASIZE);
    int i = 0, offset = 0;
    for(;i<user_num;i++)
    {
        memcpy(usr_data.data + offset, user_info[i].id, USERIDSIZE);
        offset += 20;
        if(offset >= USERDATASIZE)
            break;
    }

    usr_data.cmd = CMD_Onlineuser;
    usr_data.dst_id[0] = user_num; /* 在线用户数目 */

    for(i=0;i<user_num;i++)/* 给每一个登录的用户发送在线用户 */
    {
        write(user_info[i].sock, &usr_data, DATASIZE);
    }
}

int repeat_login(char *name)
{
    int i = 0;
    for(; i<user_num; i++)
    {
        if(0 == strcmp(user_info[i].id, name))
        {
            return -1;
        }
    }
    return 0;
}

int handle_login(USER_DATA usr_data, int sock)
{
    if(0 == validate_userinfo(usr_data.src_id, usr_data.data))
    {
        if(-1 == repeat_login(usr_data.src_id))
        {
            usr_data.cmd = CMD_REPEATLOGIN;
            write(sock, &usr_data, DATASIZE); /* 用户已登录，向客户端发送repeat */
            return -1;
        }
        else
        {
            usr_data.cmd = CMD_LOGINSUCCESS;
            write(sock, &usr_data, DATASIZE); /* 验证成功，向客户端发送0 */
        }
        /* 保存用户名和对应的socket，用于后面发送消息 */
        pthread_mutex_lock(&flag);

        memcpy(user_info[user_num].id, usr_data.src_id, USERIDSIZE);
        user_info[user_num].sock = sock;
        user_num++;

        pthread_mutex_unlock(&flag);

        send_usrinfo();

    }
    else
    {
        usr_data.cmd = CMD_LOGINFAILED;
        write(sock, &usr_data, DATASIZE); /* 验证失败，向客户端发送1, 并结束该线程 */
        return -1;
    }
}

void handle_register(USER_DATA usr_data, int sock)
{   
    int state = insert_sqlite(usr_data.src_id, usr_data.data);
    if(0 == state)
    {    
        usr_data.cmd = CMD_REGISTERSUCCESS;
        write(sock, &usr_data, DATASIZE); /* 注册成功，向客户端发送0 */
    }
    else if(-1 == state ) /* 数据库错误 */
    {
        usr_data.cmd = CMD_REGISTERFAILED;
        write(sock, &usr_data, DATASIZE); 
    }
    else if(2 == state ) /* 用户名已存在 */
    {
        usr_data.cmd = CMD_REGISTEREXISTS;
        write(sock, &usr_data, DATASIZE); 
    }
}

void *user_func(void *usersock)
{
    USER_DATA usr_data;
    
    int sock = *(int *)usersock;

    while(1)
    {
        int dstsock;
        int i;
        int n = read(sock, &usr_data, DATASIZE);
//        printf("n=%d\n",n);
//        printf("cmd:%d name:%s passwd:%s\n",usr_data.cmd,usr_data.src_id,usr_data.data);

        switch (usr_data.cmd)
        {
            case CMD_LOGIN:
//                        printf("start Login\n");
                        if(-1 == handle_login(usr_data, sock))
                        {
                            close(sock);
                            return NULL;
                        }
//                        printf("end Login\n");
                        break;
         
            case CMD_REGISTER:
            
//                        printf("start Register\n");
                        handle_register(usr_data, sock);
                        close(sock);
//                        printf("end Register\n");
                        return NULL;
                        break;
            
            case CMD_USERDATA:/* 如果是用户消息 则转发消息 */
                        
//                        printf("start userdata\n");
                        if(-1 == (dstsock = findsockbyname(usr_data.dst_id)))
                        {
//                            printf("Users are not online\n");
                        }
                        else
                        {
                            write(dstsock, &usr_data, DATASIZE);
                        }
//                        printf("end userdata\n");
                        break;
            
            case CMD_CLOSECHAT:
                       
                        i = 0; /* 如果用户关闭客户端，则删除user_info中对应的用户 */
                        for(; i<user_num; i++)
                        {
                            if(sock == user_info[i].sock)
                            {
                                break;
                            }
                        }

                        for(; i<user_num; i++)
                        {
                            memcpy(&user_info[i],&user_info[i+1],24);
                        }
                        user_num--;
                        send_usrinfo();
                            
                        close(sock);
//                        printf("closechat\n");
                        return NULL;
                        break;
        }
    }
    return NULL;
}


























